Luogu P2590 树的统计 Posted on 2018-02-07 | In 题解 | Words count in article: 1.2k | Reading time ≈ 6 基础树剖(从P3178的代码稍作修改便可A掉这里和3178差别在于线段树的过程不同和一个deep数组,具体看代码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205#include <bits/stdc++.h>#pragma GCC optimize(3)//手开O3の日常#define N 100010using namespace std;int n,m,fr,t,a,c,data[N],Size[N],num,p[2*N],fa[N],id,out[2*N],pos[2*N],h[2*N],belong[2*N],b[2*N],nt[2*N],son[N*2],deep[2*N];char s[10];struct node{ int left,right,mx; long long sum,val;};struct node tree[4*N];//线段树void pushdown(int p){ if(tree[p].val!=0) { tree[2*p].val=tree[p].val; tree[2*p+1].val=tree[p].val; tree[2*p].sum=(tree[2*p].right-tree[2*p].left+1)*tree[p].val; tree[2*p+1].sum=(tree[2*p+1].right-tree[2*p+1].left+1)*tree[p].val; tree[p].val=0; }}//lazy tag的下放void dfs(int x,int dep){ deep[x]=dep; Size[x]=1; int e=p[x]; while(e>0) { int k=b[e]; if(fa[x]!=k) { fa[k]=x;//记录每个节点的父节点,方便向上跳 dfs(k,dep+1); if(Size[k]>Size[son[x]]) son[x]=k;//不断更新该节点的重儿子 Size[x]+=Size[k];//更新该节点下方的节点数 } e=nt[e]; }}//搜索确定每个节点的深度与其下的结点个数void DFS(int x,int bh)//bh为该节点所属重链的编号(编号为该重链起点编号{ id++; pos[x]=id;//搜索序记录 out[x]=id;//这个数组请忽视(做3178后忘了改QAQ h[id]=x;//线段树上的位置 int e=p[x]; int k=0; belong[x]=bh;//记录每个节点所属的重链编号 if(son[x]) { DFS(son[x],bh);//优先搜索重儿子可得到重链 out[x]=max(out[x],out[son[x]]); } e=p[x]; while(e>0) { int kk=b[e]; if(fa[x]!=kk&&kk!=son[x]) { DFS(kk,kk); out[x]=max(out[x],out[kk]); } e=nt[e]; }//搜索轻链}void add(int u,int v){ ++num; b[num]=v; nt[num]=p[u]; p[u]=num;}//前向星存图void build(int p,int l,int r){ tree[p].left=l; tree[p].right=r; if(l==r) { tree[p].sum=data[h[l]]; tree[p].mx=data[h[l]]; return; } int mid=(l+r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); tree[p].sum=tree[2*p].sum+tree[2*p+1].sum; tree[p].mx=max(tree[2*p].mx,tree[2*p+1].mx);}//建树void change(int p,int l,int r,long long d){ if(tree[p].left==l&&tree[p].right==r) { tree[p].sum=(r-l+1)*d; tree[p].mx=d; tree[p].val=d; return; } pushdown(p); int mid=(tree[p].left+tree[p].right)/2; if(r<=mid) change(2*p,l,r,d); else if(l>mid) change(2*p+1,l,r,d); else { change(2*p,l,mid,d); change(2*p+1,mid+1,r,d); } tree[p].sum=tree[2*p].sum+tree[2*p+1].sum; tree[p].mx=max(tree[2*p].mx,tree[2*p+1].mx);}//线段树修改操作(注意此处要同时维护区间最大值与区间和long long query(int p,int l,int r){ if(tree[p].left==l&&tree[p].right==r) return tree[p].sum; pushdown(p); int mid=(tree[p].left+tree[p].right)/2; if(r<=mid) return query(2*p,l,r); else if(l>mid) return query(2*p+1,l,r); else return query(2*p,l,mid)+query(2*p+1,mid+1,r);}//查询区间和int Query(int p,int l,int r){ if(tree[p].left==l&&tree[p].right==r) return tree[p].mx; pushdown(p); int mid=(tree[p].left+tree[p].right)/2; if(r<=mid) return Query(2*p,l,r); else if(l>mid) return Query(2*p+1,l,r); else return max(Query(2*p,l,mid),Query(2*p+1,mid+1,r));}//查询区间最大值long long work(int x,int y){ long long sum=0; while(belong[x]!=belong[y]) { if(deep[belong[x]]<deep[belong[y]]) swap(x,y); sum+=query(1,pos[belong[x]],pos[x]); x=fa[belong[x]]; } if(deep[x]>deep[y]) swap(x,y); sum+=query(1,pos[x],pos[y]); return sum;}//QSUM的操作(解释见下)int Work(int x,int y){ int ans=-214748; while(belong[x]!=belong[y]) { if(deep[belong[x]]<deep[belong[y]]) swap(x,y);//比较x和y所属重链起点的深浅,将较浅的向上跳 ans=max(ans,Query(1,pos[belong[x]],pos[x])); x=fa[belong[x]]; }//如果x与y不在同一重链中,就重复执行操作 if(deep[x]>deep[y]) swap(x,y); ans=max(ans,Query(1,pos[x],pos[y]));//x与y在同一重链中最后进行一次操作 return ans;}//QMAX的操作int main(){ scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&fr,&t); add(fr,t); add(t,fr); } for(int i=1;i<=n;i++) scanf("%d",&data[i]); dfs(1,1); DFS(1,1);//先进行搜索确定了线段树上的编号再建树 build(1,1,n); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%s",s); if(s[1]=='H') { scanf("%d%d",&a,&c); change(1,pos[a],pos[a],c); } else if(s[1]=='M') { scanf("%d%d",&a,&c); printf("%d\n",Work(a,c)); } else { scanf("%d%d",&a,&c); printf("%lld\n",work(a,c)); } } return 0;} 然而跑的很慢1208ms 7.92Mb